#!/usr/bin/python
# coding=utf-8
import base64
import json
import os
import random
import string
import commands

# import requests
import sys
import urllib
import urllib2


class Setting:
    # coding=utf-8
    # 中央服务器地址
    HIERARCH_HOST = "http://192.168.31.151:9000"
    # 注册接口
    REPORT_METHOD = HIERARCH_HOST + "/ss/report"
    # 加密算法
    ENCRYPTION = "aes-256-cfb"
    # 命令集合
    SHADOWSOCKS_FUNCTION = {
        "run": "start-stop-daemon --start --quiet --pidfile /tmp/shadowsocks-{port}.pid --exec /usr/bin/ss-server -- \
         -p {port} -k {password} -m {encryption} -u -f /tmp/shadowsocks-{port}.pid",
        "status": "ps -ef | grep ss-server | grep %s | grep -v 'ps -ef'",
        "count": "blabla..."
    }
    # 开放端口
    OPEN_PORT = ["443", "8080", "80"]
    # CRONTAB_FILE = "/var/spool/cron/crontabs/root"
    CRONTAB_FILE = "#CRONTAB_FILE#"
    CRON = "*/5 * * * *"
    # 储存本机IP的文件
    IPCACHE = "/tmp/myip.cache"
    # 获取本机IP服务器
    IPSERVER = "https://api.ipify.org/?format=text"


setting = Setting()


# 根据端口检查进程信息
def checkShadowsocksProcess(port):
    info = {}
    cmd = setting.SHADOWSOCKS_FUNCTION["status"] % port
    result = shell(cmd)
    if result[0] == 0:
        process_infos = result[1].split()
        info["port"] = port
        info["user"] = process_infos[0]
        info["pid"] = process_infos[1]
        nextPwd = False
        nextEnc = False
        for v in process_infos:
            if nextPwd:
                info["password"] = v
            if nextEnc:
                info["encryption"] = v
            nextPwd = v == "-k"
            nextEnc = v == "-m"
        # 查看进程启动时间与存活时间
        cmd = "ps -eo pid,lstart,etime | grep %s" % info["pid"]
        result = shell(cmd)
        if result[0] == 0:
            time_info = result[1]
            time_info = time_info.replace(info["pid"], "")
            etime = time_info[time_info.rfind(" "):].strip()
            lstart = time_info.replace(etime, "").strip()
            info["etime"] = etime
            info["lstart"] = lstart

        return info
    return False


# 根据端口启动进程
def startShadowsocksProcess(port):
    password = randomPassword()
    info = {
        "port": port,
        "password": password,
        "encryption": setting.ENCRYPTION
    }
    cmd = setting.SHADOWSOCKS_FUNCTION["run"].format(**info)
    result = shell(cmd)
    return result[0] == 0


def stopShadowsocksProcess(port):
    info = checkShadowsocksProcess(port)
    if info:
        result = shell("kill %s" % info["pid"])
        return result[0] == 0
    return True


# 执行linux命令并获取返回结果
def shell(cmd):
    return commands.getstatusoutput(cmd)


# 随机生成密码
def randomPassword():
    return ''.join(random.sample(string.ascii_letters + string.digits, 18))


def init():
    cron_cmd = setting.CRON + " " + os.path.abspath(__file__)
    try:
        with open(Setting.CRONTAB_FILE, 'r') as cronFile:
            cronBody = cronFile.read()
            cronFile.close()
            if cron_cmd in cronBody:
                print "[INIT]定时任务正常!"
                # 重新载入配置文件
                shell("service crond reload")
                return
    except:
        pass

    try:
        with open(Setting.CRONTAB_FILE, 'w') as cronFile:
            cronFile.write(cron_cmd)
            cronFile.write("\n")
            print "[INIT]初始化定时任务成功!"
    except:
        print "[INIT]定时任务设置失败!"
        return


def myip(count=5):
    if count < 0:
        return
    try:
        ip = GET(setting.IPSERVER)
        with open(setting.IPCACHE, "w") as f:
            f.write(ip)
        return ip
    except:
        if os.path.exists(setting.IPCACHE):
            with open(setting.IPCACHE, "r") as f:
                return f.read()
        else:
            return myip(-- count)


def GET(url):
    req = urllib2.Request(url)  # url 转换成发起get 请求的url
    response = urllib2.urlopen(req, timeout=5)  # 发起GET http服务
    result = response.read()  # 把结果通过.read()函数读取出来
    response.close()
    return result


def POST(url, data):
    data = urllib.urlencode(data)
    req = urllib2.Request(url, data)
    response = urllib2.urlopen(req, timeout=5)
    result = response.read()
    response.close()
    return result


def main():
    Successful = {}
    Failured = []
    for port in setting.OPEN_PORT:
        info = checkShadowsocksProcess(port)
        if info:
            # Successful[port] = info
            pass
        else:
            if startShadowsocksProcess(port):
                info = checkShadowsocksProcess(port)
                if info:
                    Successful[port] = info
                else:
                    Failured.append(port)
            else:
                Failured.append(port)

    if len(Successful) == 0:
        return
    info = {
        "success": Successful,
        "failure": Failured
    }
    info = {"ip": myip(), "info": base64.b64encode(json.dumps(info))}
    try:
        result = POST(setting.REPORT_METHOD, info)
        print "[MAIN]状态上报成功 -> ", result
    except:
        print "[MAIN]状态上报失败 -> ", info


if __name__ == '__main__':
    init()
    main()
